#ifndef SHAPE_H
#define SHAPE_H
/// @brief 图形的定义与操作

#ifndef CARGO_H
#include "Cargo.h"
#endif

/***********************************************************
 *                                                         *
 * @brief 图形类型的枚举                                    *
 *                                                         *
 * **********************************************************/
enum class ShapeType
{
    // 图形类我们使用小写
    NONE = 'n',      // 无资源
    CIRCLE = 'o',    // 圆形
    RECTANGLE = 'r', // 方形
    STAR = 's',      // 星形
    FAN = 'f',       // 扇形
};

/***********************************************
 *                                              *
 * @brief 图形方向的枚举                         *
 *  shape 中                                    *
 * PARTS_NUM_OF_EACH_LEVEL 与这里面的数量有关     *
 *                                              *
 * **********************************************/
enum ShapePosition
{
    Shape_LEFT_DOWN,  // 左下
    Shape_LEFT_UP,    // 左上
    Shape_RIGHT_UP,   // 右上
    Shape_RIGHT_DOWN, // 右下
};

/********************************
 *                              *
 * @brief 单个部分的shape        *
 *                              *
 * ******************************/
class SinglePartShape
{
protected:
    ShapeType shape_type;
    ColorType color_type;
public:
    /// @brief 单个部分的
    /// @param shape_type 图形的形状  默认值  NONE
    /// @param color_type 颜色       默认值  NONE
    SinglePartShape(ShapeType shape_type = ShapeType::NONE,
                    ColorType color_type = ColorType::Color_NONE);

    /// @brief 被color染色
    /// @param color 上色的颜色
    void beColored(ColorType color);
    ~SinglePartShape(); // 暂时不需要自定义
    bool isNone();
    bool operator==(const SinglePartShape &);
    bool operator!=(const SinglePartShape &);

    friend class SingleLevelShape;
    friend class ShapeDefine;
};
typedef SinglePartShape SPS;

/********************************
 *                              *
 * @brief 单层的shape            *
 *                              *
 * *****************************/
class SingleLevelShape
{
protected:
    std::string hash_id;
    std::vector<SPS *> level_shape; // 整层的图形，color的初始值NONE，注意对指针的析构
public:
    /// @brief 空的一个LevelShape
    SingleLevelShape();
    /// @brief 完整的一个LevelShape
    /// @param shape_type 图形的形状
    /// @param color_type 颜色       默认值  NONE
    SingleLevelShape(ShapeType shape_type, ColorType color_type = ColorType::Color_NONE);
    SingleLevelShape(const SingleLevelShape &);
    explicit SingleLevelShape(const std::string &hash_id);
    explicit SingleLevelShape(const std::initializer_list<SPS *> &);
    /// @brief 清除图层
    void clear();
    /// @brief 析构
    virtual ~SingleLevelShape();
protected:
    /**
     *      序列化和反序列化
     *      判断是否为空
     */

    /// @brief 序列化
    /// @return 序列化后的string
    std::string serialization();

    /// @brief 反序列化 事实上只有构造函数会调用这个
    void deserialization();

    /// @brief 判断该层是否为空
    virtual bool isNone();

    /// @brief 判断该层右侧是否为空
    virtual bool isRightNone();

    /// @brief 判断该层左侧是否为空
    virtual bool isLeftNone();

    /**
     *  功能函数：染色 裁剪 堆叠 旋转
     */

    /// @brief 堆叠
    /// @param other 其他块
    /// @return 堆叠后的shape
    // virtual SingleLevelShape *stackOther(SingleLevelShape &other);

    /// @brief 被color染色
    virtual void beColored(ColorType color);

    /// @brief 被裁剪
    /// @return 被裁剪的左右半部分,注意这里不检查是否为空
    virtual std::pair<SingleLevelShape *, SingleLevelShape *> beCrop();

    /// @brief 转向
    /// @param is_clockwise 是否是顺时针方向
    void turnDirection(bool is_clockwise);

    /**
     *  重载运算符
     */

    // SingleLevelShape &operator=(const SingleLevelShape &);
    // SingleLevelShape &operator=(const SinglePartShape *other);
public:
    bool operator==(const SingleLevelShape &);
    bool operator!=(const SingleLevelShape &);

    friend class ShapeDefine;
};
typedef SingleLevelShape SLS;
/**************************************
 *                                    *
 * @brief 形状货物的定义                *
 *                                    *
 **************************************/
class ShapeDefine : public CargoDefine
{
protected:
    // 具体的图形样式，使用vector, 从底层往高层
    std::vector<SingleLevelShape *> total_shapes;
public:
    /// @brief 创建一个空的 ShapeCargo
    ShapeDefine();

    /// @brief 根据shape_type和color_type创建一个单层的 ShapeDefine
    ShapeDefine(ShapeType shape_type, ColorType color_type = ColorType::Color_NONE);
    /// @brief 拷贝函数
    ShapeDefine(const ShapeDefine &);
    /// @brief 根据hashid创建shapedefine
    explicit ShapeDefine(const std::string &);
    /// @brief 根据多层level_shape创建shapedefine
    explicit ShapeDefine(const std::initializer_list<SLS *> &);

    /// @brief 清空
    void clear() override;

    /// @brief 当且仅当 游戏结束时才会调用
    ~ShapeDefine();

protected:
    /**
     *              序列化和反序列化
     *              判断是否为空
     */

    /// @brief 序列化
    /// @return 序列化后的string
    std::string serialization() override;

    /// @brief 反序列化 事实上只有构造函数会调用这个
    void deserialization() override;

    // ShapeDefine &operator=(const ShapeDefine &other);

    /// @brief 判断该货物是否为空
    bool isNone() override;

    /// @brief 判断货物左侧是否为空
    bool isLeftNone();

    /// @brief 判断货物右侧是否为空
    bool isRightNone();

    /**
     *         功能函数：堆叠 染色 裁剪 旋转
     */

    /// @brief 堆叠器调用，以该货物为底层，在其上堆叠其他货物
    /// @todo  注意 层数 溢出的时候
    /// @return 堆叠后的块
    /// @todo 暂时还未实现
    ShapeDefine *stackOther(ShapeDefine &other);

    /// @brief 简单的一个
    ShapeDefine *simpleStackWith(ShapeDefine &other);

    /// @brief 染色器调用, 被染色
    /// @return 染色后的块
    ShapeDefine *beColored(ColorType color);

    /// @brief 裁剪器调用，被裁剪，注意返回值的析构
    /// @return 被裁剪的左右部分,注意这里不检查是否为空
    std::pair<ShapeDefine *, ShapeDefine *> beCropped();

    /// @brief 旋转
    /// @param is_clockwise 是否是顺时针
    /// @return this
    ShapeDefine *turnDirection(bool is_clockwise);

    friend class ShapeCargo;
    friend class Cargo_Manager;
};

/**************************************
 *                                    *
 * @brief 形状货物                     *
 *                                    *
 **************************************/
class ShapeCargo : public Cargo
{
public:
    ShapeCargo();
    /// @brief 这个函数只会被cargo_manager调用
    /// @param 需要构造的货物定义
    explicit ShapeCargo(ShapeDefine *);
    /**
     *  重载操作符
     */
    bool operator==(const ShapeCargo &other);
    ~ShapeCargo();
};
#endif
